/*
author:杨文超
email:yangwenchao@keynection.cn
*/
#include <stdio.h>
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "usb/usb_host.h"
#include "esp32_s3_usb_otg.h"
#include "bsp_err_check.h"
#include "geminai_log.h"

static const char *TAG = "GEMINAI_4G_AP";

static TaskHandle_t usb_host_task;  // USB Host Library task

/*OTG 设备模式*/
esp_err_t bsp_usb_mode_select_device(void)
{
    // Make sure the pin is configured
    const gpio_config_t led_io_config = {
        .pin_bit_mask = BIT64(BSP_USB_MODE_SEL),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    BSP_ERROR_CHECK_RETURN_ERR(gpio_config(&led_io_config));
    BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_USB_MODE_SEL, 0));
    return ESP_OK;
}
/*OTG host模式*/
esp_err_t bsp_usb_mode_select_host(void)
{
    // Make sure the pin is configured
    const gpio_config_t led_io_config = {
        .pin_bit_mask = BIT64(BSP_USB_MODE_SEL),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    BSP_ERROR_CHECK_RETURN_ERR(gpio_config(&led_io_config));
    BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_USB_MODE_SEL, 1));
    return ESP_OK;
}

/*host 模式设备上电*/
esp_err_t bsp_usb_host_power_mode(bsp_usb_host_power_mode_t mode, bool limit_500mA)
{
    // Make sure the pins are configured
    const gpio_config_t led_io_config = {
        .pin_bit_mask = BIT64(BSP_USB_LIMIT_EN) | BIT64(BSP_USB_DEV_VBUS_EN) | BIT64(BSP_BATTERY_BOOST_EN),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    BSP_ERROR_CHECK_RETURN_ERR(gpio_config(&led_io_config));

    // 1. Configure the limiter
    BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_USB_LIMIT_EN, limit_500mA));

    // 2. Turn power off and wait 10ms
    BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_USB_DEV_VBUS_EN, 0));
    BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_BATTERY_BOOST_EN, 0));
    vTaskDelay(pdMS_TO_TICKS(10));

    // 3. Turn on requested mode
    if (mode == BSP_USB_HOST_POWER_MODE_BATTERY) {
        BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_BATTERY_BOOST_EN, 1));
    } else if (mode == BSP_USB_HOST_POWER_MODE_USB_DEV) {
        BSP_ERROR_CHECK_RETURN_ERR(gpio_set_level(BSP_USB_DEV_VBUS_EN, 1));
    }

    return ESP_OK;
}

static void usb_lib_task(void *arg)
{
    while (1) {
        // Start handling system events
        uint32_t event_flags;
        usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
            ESP_ERROR_CHECK(usb_host_device_free_all());
        }
        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
            GEMINAI_LOGI(TAG, "USB: All devices freed");
            // Continue handling USB events to allow device reconnection
            // The only way this task can be stopped is by calling bsp_usb_host_stop()
        }
    }
}

esp_err_t bsp_usb_host_start(bsp_usb_host_power_mode_t mode, bool limit_500mA)
{
    // Configure board for host mode
    BSP_ERROR_CHECK_RETURN_ERR(bsp_usb_mode_select_host());
    BSP_ERROR_CHECK_RETURN_ERR(bsp_usb_host_power_mode(mode, limit_500mA));

    //Install USB Host driver. Should only be called once in entire application
    GEMINAI_LOGI(TAG, "Installing USB Host");
    const usb_host_config_t host_config = {
        .skip_phy_setup = false,
        .intr_flags = ESP_INTR_FLAG_LEVEL1,
    };
    BSP_ERROR_CHECK_RETURN_ERR(usb_host_install(&host_config));

    // Create a task that will handle USB library events
    if (xTaskCreate(usb_lib_task, "usb_lib", 4096, NULL, 10, &usb_host_task) != pdTRUE) {
        GEMINAI_LOGE(TAG, "Creating USB host lib task failed");
        abort();
    }

    return ESP_OK;
}

esp_err_t bsp_usb_host_stop(void)
{
    usb_host_uninstall();
    if (usb_host_task) {
        vTaskSuspend(usb_host_task);
        vTaskDelete(usb_host_task);
    }
    return bsp_usb_host_power_mode(BSP_USB_HOST_POWER_MODE_OFF, false);
}
